package society.framework.core.xml;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import society.framework.core.BaseAutomaton;
import society.framework.core.Callback;
import society.framework.core.MessageList;
import society.framework.core.communication.Message;
import society.framework.core.communication.MessageRouter;

/**
 * Abstract automaton which is dynamically written. The code is made of different classes which represent instructions.<br/>
 * It must be serialized/deserialized entirely to/from XML.
 * @author Micu Andrei
 *
 */
public abstract class BaseXMLAutomaton extends BaseAutomaton {
	protected HashMap<String, Object> variables;				//holds the variables in the automaton
	protected String name;										//the name of the automaton (used for serialization)
	protected boolean registerAtStart;
	
	public BaseXMLAutomaton() {
		this.variables = new HashMap<String, Object>();
		this.name = null;
		this.registerAtStart = false;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	

	public boolean isRegisterAtStart() {
		return registerAtStart;
	}

	public void setRegisterAtStart(boolean registerAtStart) {
		this.registerAtStart = registerAtStart;
	}
	
	/**
	 * Method that creates and starts the automaton thread.<br/>
	 * In case the thread is created and alive it will attempt to stop it and start a new one
	 * (in this case the method returns immediately after it attempts to stop the automaton).
	 */
	public void start() {
		if(automatonThread!=null && automatonThread.isAlive()){
			this.stopSafely(new Callback() {
				
				public void handleMethod() {
					if(registerAtStart){
						MessageRouter.getInstance().subscribe(BaseXMLAutomaton.this.getName(), BaseXMLAutomaton.this);
					}
					automatonThread = new AutomatonThread();
					automatonThread.setName("AutomatonThread_"+this.getClass().getSimpleName());
					automatonThread.start();
				}
				
			});
		} else {
			if(registerAtStart){
				MessageRouter.getInstance().subscribe(BaseXMLAutomaton.this.getName(), BaseXMLAutomaton.this);
			}
			automatonThread = new AutomatonThread();
			automatonThread.setName("AutomatonThread_"+this.getClass().getSimpleName());
			automatonThread.start();
		}
	}
	
	
	
	
	/* STATE / TRANSITION CLASSES */


	/**
	 * Extension of the State class which executes a state code in an XML automaton.
	 * @author Micu Andrei
	 *
	 */
	protected class XMLState extends State implements CodeContainer{
		public Instruction instruction;
		
		public XMLState() {}

		/**
		 * Method which runs the instructions in the state
		 */
		public void stateCode(){
			if(instruction!=null){
				instruction.code();
			}
		}

		public void addInstruction(Instruction instruction) {
			if(this.instruction!=null){
				if(this.instruction instanceof InstructionBlock){
					((InstructionBlock)this.instruction).addInstruction(instruction);
				} else {
					InstructionBlock instructionBlock = new InstructionBlock();
					instructionBlock.addInstruction(this.instruction);
					instructionBlock.addInstruction(instruction);
					this.instruction = instructionBlock;
				}
			} else {
				this.instruction = instruction;
			}
		}

		public Instruction removeInstruction() {
			if(this.instruction!=null){
				if(this.instruction instanceof InstructionBlock){
					InstructionBlock instructionBlock = (InstructionBlock) instruction;
					if(instructionBlock.instructions.size()>2){
						return instructionBlock.removeInstruction();
					} else {
						Instruction lastInstruction = instructionBlock.removeInstruction();
						this.instruction = instructionBlock.removeInstruction();
						return lastInstruction;
					}
				} else {
					Instruction lastInstruction = this.instruction;
					this.instruction = null;
					return lastInstruction;
				}
			} else {
				return null;
			}
		}
	}
	
	/**
	 * Extension of the Transition class which executes a transition in an XML automaton.
	 * @author Micu Andrei
	 *
	 */
	protected class XMLTransition extends Transition implements CodeContainer{
		public Instruction instruction;
		
		public XMLTransition() {}

		/**
		 * Method that runs the instructions and performs the transition to the next state
		 * @return - the name of the next state (if the conditions in the code are satisfied) or null (if the
		 * conditions are not satisfied)
		 */
		public String transitionCode(){
			if(instruction!=null){
				return (String) instruction.code();
			} else {
				return null;
			}
		}

		public void addInstruction(Instruction instruction) {
			if(this.instruction!=null){
				if(this.instruction instanceof InstructionBlock){
					((InstructionBlock)this.instruction).addInstruction(instruction);
				} else {
					InstructionBlock instructionBlock = new InstructionBlock();
					instructionBlock.addInstruction(this.instruction);
					instructionBlock.addInstruction(instruction);
					this.instruction = instructionBlock;
				}
			} else {
				this.instruction = instruction;
			}
		}

		public Instruction removeInstruction() {
			if(this.instruction!=null){
				if(this.instruction instanceof InstructionBlock){
					InstructionBlock instructionBlock = (InstructionBlock) instruction;
					if(instructionBlock.instructions.size()>2){
						return instructionBlock.removeInstruction();
					} else {
						Instruction lastInstruction = instructionBlock.removeInstruction();
						this.instruction = instructionBlock.removeInstruction();
						return lastInstruction;
					}
				} else {
					Instruction lastInstruction = this.instruction;
					this.instruction = null;
					return lastInstruction;
				}
			} else {
				return null;
			}
		}
	}
	
	/**
	 * Extension of the TransitionGroup class which executes a transition group in an XML automaton.
	 * @author Micu Andrei
	 *
	 */
	protected class XMLTransitionGroup extends TransitionGroup implements CodeContainer{
		public Instruction instruction;
		
		public XMLTransitionGroup() {}
		
		/**
		 * Method that runs the instructions and performs the transition to the next state
		 * @return - the name of the next state (if the conditions in the code are satisfied) or null (if the
		 * conditions are not satisfied)
		 */
		public String transitionCode(){
			if(instruction!=null){
				return (String) instruction.code();
			} else {
				return null;
			}
		}

		public void addInstruction(Instruction instruction) {
			if(this.instruction!=null){
				if(this.instruction instanceof InstructionBlock){
					((InstructionBlock)this.instruction).addInstruction(instruction);
				} else {
					InstructionBlock instructionBlock = new InstructionBlock();
					instructionBlock.addInstruction(this.instruction);
					instructionBlock.addInstruction(instruction);
					this.instruction = instructionBlock;
				}
			} else {
				this.instruction = instruction;
			}
		}

		public Instruction removeInstruction() {
			if(this.instruction!=null){
				if(this.instruction instanceof InstructionBlock){
					InstructionBlock instructionBlock = (InstructionBlock) instruction;
					if(instructionBlock.instructions.size()>2){
						return instructionBlock.removeInstruction();
					} else {
						Instruction lastInstruction = instructionBlock.removeInstruction();
						this.instruction = instructionBlock.removeInstruction();
						return lastInstruction;
					}
				} else {
					Instruction lastInstruction = this.instruction;
					this.instruction = null;
					return lastInstruction;
				}
			} else {
				return null;
			}
		}
	}
	
	/* ******************** INSTRUCTION CLASSES ******************** */
	
	protected enum SpecialSymbols { BREAK, CONTINUE };
	
	/**
	 * Interface which is implemented by instructions in an XMLState or an XMLTransition.
	 * @author Micu Andrei
	 * 
	 */
	protected interface Instruction{
		/**
		 * Function called when the instruction is executed
		 * @return - the result of the instruction which can be any value.
		 */
		public Object code();
	}
	
	/**
	 * Interface which a class can implement in order to mark that it contains code.
	 * @author Micu Andrei
	 *
	 */
	protected interface CodeContainer{
		/**
		 * Function that adds an instruction to the tail of the list of instructions in the implementing class.
		 * @param instruction - the instruction to be added
		 */
		public void addInstruction(Instruction instruction);
		
		/**
		 * Function that removes an instruction from the tail of the list of instructions in the implementing class.
		 * @return - the removed instruction
		 */
		public Instruction removeInstruction();
	}

	/**
	 * Class which represents a block of instructions in an XMLState or an XMLTransition.
	 * @author Micu Andrei
	 * 
	 */
	protected class InstructionBlock implements Instruction, CodeContainer{
		public ArrayList<Instruction> instructions = new ArrayList<Instruction>();
		
		/**
		 * Function called when the instruction block is executed. Execution is terminated when an instruction returns a value.
		 * @return - this value can be null (which represents continuing the execution with the next instruction), a returned value or a
		 * LoopSpecialSymbols.BREAK/LoopSpecialSymbols.CONTINUE symbol which will be interpreted by the loop that contains the block.
		 */
		public Object code() {
			Object returnedValue = null;
			for(Instruction i : instructions){
				returnedValue = i.code();
				if(returnedValue!=null) break;
			}
			return returnedValue;
		}

		public void addInstruction(Instruction instruction) {
			instructions.add(instruction);
		}

		public Instruction removeInstruction() {
			return instructions.remove(instructions.size()-1);
		}
		
	}

	/* ******************** LOOP INSTRUCTION CLASSES ******************** */
	
	/**
	 * Class which represents a while loop. It contains a test instruction which must return a Boolean value and a repeat
	 * instruction which is executed until the test instruction returns false.<br />
	 * The repeat instruction can be a single instruction or an instruction block. In case of an instruction block if the
	 * block returns LoopSpecialSymbols.CONTINUE or LoopSpecialSymbols.BREAK the specified action is taken. If it returns
	 * null, the while continues with the test instruction. If it returns anything else then it is considered a return value.
	 * @author Micu Andrei
	 *
	 */
	protected class WhileInstruction implements Instruction, CodeContainer{
		public Instruction testInstruction, repeatInstruction;

		public Object code() {
			Object instructionResult = null;
			while((Boolean) testInstruction.code()){
				if(repeatInstruction!=null){
					instructionResult = repeatInstruction.code();
				}
				if(instructionResult != null){
					if(instructionResult.equals(SpecialSymbols.BREAK)){
						break;
					} else if(!instructionResult.equals(SpecialSymbols.CONTINUE)){
						return instructionResult;
					}
				}
			}
			return null;
		}

		public void addInstruction(Instruction instruction) {
			if(this.repeatInstruction!=null){
				if(this.repeatInstruction instanceof InstructionBlock){
					((InstructionBlock)this.repeatInstruction).addInstruction(instruction);
				} else {
					InstructionBlock instructionBlock = new InstructionBlock();
					instructionBlock.addInstruction(this.repeatInstruction);
					instructionBlock.addInstruction(instruction);
					this.repeatInstruction = instructionBlock;
				}
			} else {
				this.repeatInstruction = instruction;
			}
		}

		public Instruction removeInstruction() {
			if(this.repeatInstruction!=null){
				if(this.repeatInstruction instanceof InstructionBlock){
					InstructionBlock instructionBlock = (InstructionBlock) repeatInstruction;
					if(instructionBlock.instructions.size()>2){
						return instructionBlock.removeInstruction();
					} else {
						Instruction lastInstruction = instructionBlock.removeInstruction();
						this.repeatInstruction = instructionBlock.removeInstruction();
						return lastInstruction;
					}
				} else {
					Instruction lastInstruction = this.repeatInstruction;
					this.repeatInstruction = null;
					return lastInstruction;
				}
			} else {
				return null;
			}
		}
		
	}
	
	/**
	 * Class which represents a do-while loop. It contains a test instruction which must return a Boolean value and a repeat
	 * instruction which is executed first and then until the test instruction returns false.<br />
	 * The repeat instruction can be a single instruction or an instruction block. In case of an instruction block if the
	 * block returns LoopSpecialSymbols.CONTINUE or LoopSpecialSymbols.BREAK the specified action is taken. If it returns
	 * null, the while continues with the test instruction. If it returns anything else then it is considered a return value.
	 * @author Micu Andrei
	 *
	 */
	protected class DoWhileInstruction implements Instruction, CodeContainer{
		public Instruction testInstruction, repeatInstruction;

		public Object code() {
			Object instructionResult = null;
			do {
				if(repeatInstruction!=null){
					instructionResult = repeatInstruction.code();
				}
				if(instructionResult != null){
					if(instructionResult.equals(SpecialSymbols.BREAK)){
						break;
					} else if(!instructionResult.equals(SpecialSymbols.CONTINUE)){
						return instructionResult;
					}
				}
			} while((Boolean) testInstruction.code());
			return null;
		}

		public void addInstruction(Instruction instruction) {
			if(this.repeatInstruction!=null){
				if(this.repeatInstruction instanceof InstructionBlock){
					((InstructionBlock)this.repeatInstruction).addInstruction(instruction);
				} else {
					InstructionBlock instructionBlock = new InstructionBlock();
					instructionBlock.addInstruction(this.repeatInstruction);
					instructionBlock.addInstruction(instruction);
					this.repeatInstruction = instructionBlock;
				}
			} else {
				this.repeatInstruction = instruction;
			}
		}

		public Instruction removeInstruction() {
			if(this.repeatInstruction!=null){
				if(this.repeatInstruction instanceof InstructionBlock){
					InstructionBlock instructionBlock = (InstructionBlock) repeatInstruction;
					if(instructionBlock.instructions.size()>2){
						return instructionBlock.removeInstruction();
					} else {
						Instruction lastInstruction = instructionBlock.removeInstruction();
						this.repeatInstruction = instructionBlock.removeInstruction();
						return lastInstruction;
					}
				} else {
					Instruction lastInstruction = this.repeatInstruction;
					this.repeatInstruction = null;
					return lastInstruction;
				}
			} else {
				return null;
			}
		}
		
	}
	
	/**
	 * Class which represents a for loop. It contains an assign instruction which is executed at the beginning, a test 
	 * instruction which must return a Boolean value, a stepInstruction which is executed after each repeat instruction
	 * execution and a repeat instruction which is executed until the test instruction returns false.<br />
	 * The repeat instruction can be a single instruction or an instruction block. In case of an instruction block if the
	 * block returns LoopSpecialSymbols.CONTINUE or LoopSpecialSymbols.BREAK the specified action is taken. If it returns
	 * null, the while continues with the step and test instructions. If it returns anything else then it is considered 
	 * a return value.
	 * @author Micu Andrei
	 *
	 */
	protected class ForInstruction implements Instruction, CodeContainer{
		public Instruction assignInstruction, testInstruction, stepInstruction, repeatInstruction;

		public Object code() {
			Object instructionResult = null;
			assignInstruction.code();
			while((Boolean) testInstruction.code()){
				if(repeatInstruction!=null){
					instructionResult = repeatInstruction.code();
				}
				if(instructionResult != null){
					if(instructionResult.equals(SpecialSymbols.BREAK)){
						break;
					} else if(!instructionResult.equals(SpecialSymbols.CONTINUE)){
						return instructionResult;
					}
				}
				stepInstruction.code();
			}
			return null;
		}

		public void addInstruction(Instruction instruction) {
			if(this.repeatInstruction!=null){
				if(this.repeatInstruction instanceof InstructionBlock){
					((InstructionBlock)this.repeatInstruction).addInstruction(instruction);
				} else {
					InstructionBlock instructionBlock = new InstructionBlock();
					instructionBlock.addInstruction(this.repeatInstruction);
					instructionBlock.addInstruction(instruction);
					this.repeatInstruction = instructionBlock;
				}
			} else {
				this.repeatInstruction = instruction;
			}
		}

		public Instruction removeInstruction() {
			if(this.repeatInstruction!=null){
				if(this.repeatInstruction instanceof InstructionBlock){
					InstructionBlock instructionBlock = (InstructionBlock) repeatInstruction;
					if(instructionBlock.instructions.size()>2){
						return instructionBlock.removeInstruction();
					} else {
						Instruction lastInstruction = instructionBlock.removeInstruction();
						this.repeatInstruction = instructionBlock.removeInstruction();
						return lastInstruction;
					}
				} else {
					Instruction lastInstruction = this.repeatInstruction;
					this.repeatInstruction = null;
					return lastInstruction;
				}
			} else {
				return null;
			}
		}
		
	}

	/* ******************** CONDITIONAL INSTRUCTION CLASSES ******************** */

	/**
	 * Class which represents an if-else instruction. The test instruction must return a Boolean value and it is executed
	 * first. The succeed instruction is executed if the test function returns true and the fail instruction is executed
	 * if the test function returns false. If there is no fail instruction (null) then the return value in case of fail is
	 * null, which means continuing the execution in the containing block. <br />
	 * The succeed and fail instructions can be single instructions or instruction blocks.
	 * 
	 * @author Micu Andrei
	 *
	 */
	protected class IfElseInstruction implements Instruction, CodeContainer{
		public Instruction testInstruction, succeedInstruction, failInstruction;

		public Object code() {
			if((Boolean) testInstruction.code()){
				if(succeedInstruction!=null){
					return succeedInstruction.code();
				}
			} else {
				if(failInstruction!=null){
					return failInstruction.code();
				}
			}
			return null;
		}

		public void addInstruction(Instruction instruction) {
			if(this.succeedInstruction!=null){
				if(this.succeedInstruction instanceof InstructionBlock){
					((InstructionBlock)this.succeedInstruction).addInstruction(instruction);
				} else {
					InstructionBlock instructionBlock = new InstructionBlock();
					instructionBlock.addInstruction(this.succeedInstruction);
					instructionBlock.addInstruction(instruction);
					this.succeedInstruction = instructionBlock;
				}
			} else {
				this.succeedInstruction = instruction;
			}
		}

		public Instruction removeInstruction() {
			if(this.succeedInstruction!=null){
				if(this.succeedInstruction instanceof InstructionBlock){
					InstructionBlock instructionBlock = (InstructionBlock) succeedInstruction;
					if(instructionBlock.instructions.size()>2){
						return instructionBlock.removeInstruction();
					} else {
						Instruction lastInstruction = instructionBlock.removeInstruction();
						this.succeedInstruction = instructionBlock.removeInstruction();
						return lastInstruction;
					}
				} else {
					Instruction lastInstruction = this.succeedInstruction;
					this.succeedInstruction = null;
					return lastInstruction;
				}
			} else {
				return null;
			}
		}
		
	}
	

	/**
	 * Class which represents a switch instruction. The argument instruction must return a value to compare with the
	 * ones in the case instructions. Once the argument matches a case value the case instructions begin to execute until
	 * one of them returns a BREAK or a value. The default instruction is executed at the end, if no other case returned
	 * BREAK or value.
	 * 
	 * @author Micu Andrei
	 *
	 */
	protected class SwitchInstruction implements Instruction{
		public ArrayList<CaseInstruction> caseInstructionsList = new ArrayList<CaseInstruction>();
		public Instruction argumentInstruction, defaultInstruction;

		public Object code() {
			int i=0, size = caseInstructionsList.size();
			Object argument = argumentInstruction.code(), aux=null;
			while(i < size && (!caseInstructionsList.get(i).label.code().equals(argument))){
				++i;
			}
			while(i < size){
				if(caseInstructionsList.get(i) != null){
					aux = caseInstructionsList.get(i).code();
				}
				if(aux != null){
					return aux.equals(SpecialSymbols.BREAK) ? null : aux;
				}
				++i;
			}
			if(defaultInstruction != null){
				aux = defaultInstruction.code();
			}
			if(aux != null){
				return aux.equals(SpecialSymbols.BREAK) ? null : aux;
			} else {
				return null;
			}
		}
		
	}
	
	/**
	 * Class which represents a case instruction. This instruction has a label to be identified in the case.
	 * It acts like a normal Instruction which can contain inside code.
	 * 
	 * @author Micu Andrei
	 *
	 */
	protected class CaseInstruction implements Instruction, CodeContainer{
		public Instruction label;
		public Instruction instruction;

		public Object code(){
			if(instruction!=null){
				return instruction.code();
			} else {
				return null;
			}
		}

		public void addInstruction(Instruction instruction) {
			if(this.instruction!=null){
				if(this.instruction instanceof InstructionBlock){
					((InstructionBlock)this.instruction).addInstruction(instruction);
				} else {
					InstructionBlock instructionBlock = new InstructionBlock();
					instructionBlock.addInstruction(this.instruction);
					instructionBlock.addInstruction(instruction);
					this.instruction = instructionBlock;
				}
			} else {
				this.instruction = instruction;
			}
		}

		public Instruction removeInstruction() {
			if(this.instruction!=null){
				if(this.instruction instanceof InstructionBlock){
					InstructionBlock instructionBlock = (InstructionBlock) instruction;
					if(instructionBlock.instructions.size()>2){
						return instructionBlock.removeInstruction();
					} else {
						Instruction lastInstruction = instructionBlock.removeInstruction();
						this.instruction = instructionBlock.removeInstruction();
						return lastInstruction;
					}
				} else {
					Instruction lastInstruction = this.instruction;
					this.instruction = null;
					return lastInstruction;
				}
			} else {
				return null;
			}
		}
		
	}
	
	
	/* ******************** VALUE INSTRUCTION CLASSES ******************** */
	
	/**
	 * Class which represents a value. If it is a direct instruction in an instruction block then it's considered
	 * a return value for the block. If it's part of an expression inside an instruction then the instruction is 
	 * considered a normal value.
	 * @author Micu Andrei
	 *
	 */
	protected class ValueInstruction implements Instruction{
		public Object value;

		public Object code() {
			return value;
		}
		
	}
	
	/**
	 * Class which represents a variable value. If it is a direct instruction in an instruction block then it's considered
	 * a return value for the block. If it's part of an expression inside an instruction then the instruction is considered
	 * a normal variable value.
	 * @author Micu Andrei
	 *
	 */
	protected class VariableInstruction implements Instruction{
		public String name;
		
		public Object code(){
			return variables.get(name);
		}
	}
	
	/**
	 * Class which represents a variable with index values. If it is a direct instruction in an instruction block then
	 * it's considered a return value for the block. If it's part of an expression inside an instruction then the 
	 * instruction is considered a normal variable value.
	 * @author Micu Andrei
	 *
	 */
	protected class VariableWithIndexInstruction extends VariableInstruction{
		public ArrayList<Instruction> indexValues = new ArrayList<BaseXMLAutomaton.Instruction>();

		@SuppressWarnings("unchecked")
		public Object code() {
			HashMap<Object, Object> currentVariable = (HashMap<Object, Object>)variables.get(name);
			for(int i=0; i<indexValues.size()-1; i++){
				currentVariable = (HashMap<Object, Object>) currentVariable.get(indexValues.get(i).code());
			}
			return currentVariable.get(indexValues.get(indexValues.size()-1).code());
		}
		
	}
	

	/* ******************** OPERATION INSTRUCTION CLASSES ******************** */
	
	/**
	 * A class used to identify that an instruction has one operand to complete in the expression construction process.
	 * @author Micu Andrei
	 *
	 */
	protected abstract class OneOperandInstruction implements Instruction{
		public Instruction operand;
	}
	
	/**
	 * A class used to identify that an instruction has two operands to complete in the expression construction process.
	 * @author Micu Andrei
	 *
	 */
	protected abstract class TwoOperandsInstruction implements Instruction{
		public Instruction leftOperand, rightOperand;
	}
	

	/**
	 * Class which represents an assign instruction. The leftOperand is an instruction containing the name of the 
	 * variable to be assigned to. It can be both a VariableInstruction or a VariableWithIndexInstruction. In case
	 * it's a VariableWithIndexInstruction the maps are created automatically. If the variable name doesn't exist 
	 * it is created automatically. The rightOperand is an instruction which must return the assigned value. The
	 * returned value is the leftOpernad.
	 * @author Micu Andrei
	 *
	 */
	protected class AssignInstruction extends TwoOperandsInstruction{

		@SuppressWarnings("unchecked")
		public Object code() {
			if(leftOperand instanceof VariableWithIndexInstruction){
				VariableWithIndexInstruction firstVariable = ((VariableWithIndexInstruction)leftOperand);
				Object currentVariable = variables.get(firstVariable.name);
				if(currentVariable == null || !(currentVariable instanceof HashMap<?, ?>)){
					currentVariable = new HashMap<Object, Object>();
					variables.put(firstVariable.name, currentVariable);
				}
				
				Object currentIndex = null;
				HashMap<Object, Object> currentHashMap = (HashMap<Object, Object>) currentVariable;
				
				for(int i=0; i<firstVariable.indexValues.size()-1; i++){
					currentIndex = firstVariable.indexValues.get(i).code();
					currentVariable = currentHashMap.get(currentIndex);
					if(currentVariable == null || !(currentVariable instanceof HashMap<?, ?>)){
						currentVariable = new HashMap<Object, Object>();
						currentHashMap.put(currentIndex, currentVariable);
					}
					currentHashMap = (HashMap<Object, Object>) currentVariable;
				}
				currentIndex = firstVariable.indexValues.get(firstVariable.indexValues.size()-1).code();
				currentHashMap.put(currentIndex, rightOperand.code());
			} else {
				variables.put(((VariableInstruction)leftOperand).name, rightOperand.code());
			}
			return leftOperand;
		}
		
	}
	
	/**
	 * Class which represents the addition(+) operator. The left operand and the right operand can be one of the following
	 * types: Integer, Double or String. When the left or right operand is String, the other can be Boolean.
	 * @author Micu Andrei
	 *
	 */
	protected class AdditionInstruction extends TwoOperandsInstruction{

		public Object code() {
			Object left = leftOperand.code();
			Object right = rightOperand.code();
			if(left instanceof Integer){
				if(right instanceof Integer){
					return (Integer)left + (Integer)right;
				} else if(right instanceof Double) {
					return (Integer)left + (Double)right;
				} else if(right instanceof String) {
					return (Integer)left + (String)right;
				}
			} else if(left instanceof Double) {
				if(right instanceof Integer){
					return (Double)left + (Integer)right;
				} else if(right instanceof Double) {
					return (Double)left + (Double)right;
				} else if(right instanceof String) {
					return (Double)left + (String)right;
				}
			} else if(left instanceof String) {
				if(right instanceof Integer){
					return (String)left + (Integer)right;
				} else if(right instanceof Double) {
					return (String)left + (Double)right;
				} else if(right instanceof String) {
					return (String)left + (String)right;
				} else if(right instanceof Boolean) {
					return (String)left + (Boolean)right;
				}
			} else if(left instanceof Boolean && right instanceof String){
				return (Boolean)left + (String)right;
			}
			return null;
		}
		
	}
	
	/**
	 * Class which represents the subtraction(-) operator. The left operand and the right operand can be one of the following
	 * types: Integer and Double.
	 * @author Micu Andrei
	 *
	 */
	protected class SubtractionInstruction extends TwoOperandsInstruction{

		public Object code() {
			Object left = leftOperand.code();
			Object right = rightOperand.code();
			if(left instanceof Integer){
				if(right instanceof Integer){
					return (Integer)left - (Integer)right;
				} else if(right instanceof Double) {
					return (Integer)left - (Double)right;
				}
			} else if(left instanceof Double) {
				if(right instanceof Integer){
					return (Double)left - (Integer)right;
				} else if(right instanceof Double) {
					return (Double)left - (Double)right;
				}
			}
			return null;
		}
		
	}
	
	/**
	 * Class which represents the multiplication(*) operator. The left operand and the right operand can be one of the following
	 * types: Integer and Double.
	 * @author Micu Andrei
	 *
	 */
	protected class MultiplicationInstruction extends TwoOperandsInstruction{

		public Object code() {
			Object left = leftOperand.code();
			Object right = rightOperand.code();
			if(left instanceof Integer){
				if(right instanceof Integer){
					return (Integer)left * (Integer)right;
				} else if(right instanceof Double) {
					return (Integer)left * (Double)right;
				}
			} else if(left instanceof Double) {
				if(right instanceof Integer){
					return (Double)left * (Integer)right;
				} else if(right instanceof Double) {
					return (Double)left * (Double)right;
				}
			}
			return null;
		}
		
	}
	
	/**
	 * Class which represents the division(/) operator. The left operand and the right operand can be one of the following
	 * types: Integer and Double.
	 * @author Micu Andrei
	 *
	 */
	protected class DivisionInstruction extends TwoOperandsInstruction{

		public Object code() {
			Object left = leftOperand.code();
			Object right = rightOperand.code();
			if(left instanceof Integer){
				if(right instanceof Integer){
					return (Integer)left / (Integer)right;
				} else if(right instanceof Double) {
					return (Integer)left / (Double)right;
				}
			} else if(left instanceof Double) {
				if(right instanceof Integer){
					return (Double)left / (Integer)right;
				} else if(right instanceof Double) {
					return (Double)left / (Double)right;
				}
			}
			return null;
		}
		
	}
	
	/**
	 * Class which represents the modulo(%) operator. The left operand and the right operand can be one of the following
	 * types: Integer.
	 * @author Micu Andrei
	 *
	 */
	protected class ModuloInstruction extends TwoOperandsInstruction{

		public Object code() {
			return (Integer) leftOperand.code() % (Integer) rightOperand.code();
		}
		
	}
	
	/* ******************** BOOLEAN OPERATION INSTRUCTION CLASSES ******************** */

	/**
	 * Class which represents the less(<) operator. The left operand and the right operand can be one of the following
	 * types: Integer and Double.
	 * @author Micu Andrei
	 *
	 */
	protected class LessInstruction extends TwoOperandsInstruction{

		public Object code() {
			Object left = leftOperand.code();
			Object right = rightOperand.code();
			if(left instanceof Integer){
				if(right instanceof Integer){
					return (Integer)left < (Integer)right;
				} else if(right instanceof Double) {
					return (Integer)left < (Double)right;
				}
			} else if(left instanceof Double) {
				if(right instanceof Integer){
					return (Double)left < (Integer)right;
				} else if(right instanceof Double) {
					return (Double)left < (Double)right;
				}
			}
			return null;
		}
		
	}
	
	/**
	 * Class which represents the less or equal(<=) operator. The left operand and the right operand can be one of the following
	 * types: Integer and Double.
	 * @author Micu Andrei
	 *
	 */
	protected class LessOrEqualInstruction extends TwoOperandsInstruction{

		public Object code() {
			Object left = leftOperand.code();
			Object right = rightOperand.code();
			if(left instanceof Integer){
				if(right instanceof Integer){
					return (Integer)left <= (Integer)right;
				} else if(right instanceof Double) {
					return (Integer)left <= (Double)right;
				}
			} else if(left instanceof Double) {
				if(right instanceof Integer){
					return (Double)left <= (Integer)right;
				} else if(right instanceof Double) {
					return (Double)left <= (Double)right;
				}
			}
			return null;
		}
		
	}
	
	/**
	 * Class which represents the greater(>) operator. The left operand and the right operand can be one of the following
	 * types: Integer and Double.
	 * @author Micu Andrei
	 *
	 */
	protected class GreaterInstruction extends TwoOperandsInstruction{

		public Object code() {
			Object left = leftOperand.code();
			Object right = rightOperand.code();
			if(left instanceof Integer){
				if(right instanceof Integer){
					return (Integer)left > (Integer)right;
				} else if(right instanceof Double) {
					return (Integer)left > (Double)right;
				}
			} else if(left instanceof Double) {
				if(right instanceof Integer){
					return (Double)left > (Integer)right;
				} else if(right instanceof Double) {
					return (Double)left > (Double)right;
				}
			}
			return null;
		}
		
	}
	
	/**
	 * Class which represents the greater or equal(>=) operator. The left operand and the right operand can be one of the following
	 * types: Integer and Double.
	 * @author Micu Andrei
	 *
	 */
	protected class GreaterOrEqualInstruction extends TwoOperandsInstruction{

		public Object code() {
			Object left = leftOperand.code();
			Object right = rightOperand.code();
			if(left instanceof Integer){
				if(right instanceof Integer){
					return (Integer)left >= (Integer)right;
				} else if(right instanceof Double) {
					return (Integer)left >= (Double)right;
				}
			} else if(left instanceof Double) {
				if(right instanceof Integer){
					return (Double)left >= (Integer)right;
				} else if(right instanceof Double) {
					return (Double)left >= (Double)right;
				}
			}
			return null;
		}
		
	}
	
	/**
	 * Class which represents the equality(==) operator. The left operand and the right operand can be one of the following
	 * types: Boolean, Integer, Double and String.
	 * @author Micu Andrei
	 *
	 */
	protected class EqualsInstruction extends TwoOperandsInstruction{

		public Object code() {
			return leftOperand.code().equals(rightOperand.code());
		}
		
	}
	
	/**
	 * Class which represents the non-equality(!=) operator. The left operand and the right operand can be one of the following
	 * types: Boolean, Integer, Double and String.
	 * @author Micu Andrei
	 *
	 */
	protected class NotEqualsInstruction extends TwoOperandsInstruction{

		public Object code() {
			return !leftOperand.code().equals(rightOperand.code());
		}
		
	}
	
	/**
	 * Class which represents the and(&&) operator. The left operand and the right operand can be one of the following
	 * types: Boolean.
	 * @author Micu Andrei
	 *
	 */
	protected class AndInstruction extends TwoOperandsInstruction{

		public Object code() {
			return (Boolean)leftOperand.code() && (Boolean)rightOperand.code();
		}
		
	}
	
	/**
	 * Class which represents the or(||) operator. The left operand and the right operand can be one of the following
	 * types: Boolean.
	 * @author Micu Andrei
	 *
	 */
	protected class OrInstruction extends TwoOperandsInstruction{

		public Object code() {
			return (Boolean)leftOperand.code() || (Boolean)rightOperand.code();
		}
		
	}
	
	/**
	 * Class which represents the not(!) operator. The argument can be one of the following types: Boolean.
	 * @author Micu Andrei
	 *
	 */
	protected class NotInstruction extends OneOperandInstruction{

		public Object code() {
			return !(Boolean)operand.code();
		}
		
	}


	/* ******************** FUNCION-LIKE INSTRUCTION CLASSES ******************** */
	
	/**
	 * Abstract class which must be extended in order to create a function-like instruction.
	 * It contains an array of parameters which is used when calling the instruction.
	 * @author Micu Andrei
	 *
	 */
	protected abstract class FunctionInstruction implements Instruction{
		public Instruction[] parameters;
	}

	/**
	 * Class which represents the getCurrentMessageFrom() instruction. It returns currentMessage.from value.
	 * @author Micu Andrei
	 *
	 */
	protected class GetCurrentMessageFromInstruction extends FunctionInstruction{
		
		public Object code(){
			return currentMessage.from;
		}
	}
	
	/**
	 * Class which represents the getCurrentMessageData() instruction. It returns currentMessage.data value.
	 * @author Micu Andrei
	 *
	 */
	protected class GetCurrentMessageDataInstruction extends FunctionInstruction{
		
		public Object code(){
			return currentMessage.data;
		}
	}

	/**
	 * Class which represents the isCurrentMessageNull() instruction. It returns a Boolean that is true if the current
	 * message is null and false otherwise.
	 * @author Micu Andrei
	 *
	 */
	protected class IsCurrentMessageNullInstruction extends FunctionInstruction{

		public Object code() {
			return currentMessage==null;
		}
	}
	
	/**
	 * Class which represents the executeTransition() instruction. It returns the transition result.<br/>
	 * Parameters:<br/>
	 * 0 -> instruction returning the name of the transition to be executed
	 * @author Micu Andrei
	 *
	 */
	protected class ExecuteTransitionInstruction extends FunctionInstruction{
		public TransitionGroup owner;

		public Object code() {
			return owner.transitions.get(parameters[0].code()).transitionCode();
		}
	}
	
	/**
	 * Class which represents the size() instruction. It returns the number of elements in a Map as an Integer.<br/>
	 * Parameters:<br/>
	 * 0 -> the Map object
	 * @author Micu Andrei
	 *
	 */
	protected class SizeInstruction extends FunctionInstruction{

		public Object code() {
			VariableInstruction variable = (VariableInstruction) parameters[0];
			HashMap<?, ?> map = (HashMap<?, ?>) variables.get(variable.name);
			if(variable instanceof VariableWithIndexInstruction){
				for(Instruction index : ((VariableWithIndexInstruction)variable).indexValues){
					map = (HashMap<?, ?>) map.get(index.code());
				}
			}
			return getElementsNumber(map);
		}
		
		public Integer getElementsNumber(HashMap<?, ?> map){
			Integer number = 0;
			for(Entry<?, ?> entry : map.entrySet()){
				number++;
				if(entry.getValue() instanceof HashMap<?, ?>){
					number+=getElementsNumber((HashMap<?, ?>) entry.getValue());
				}
			}
			return number;
		}
	}
	
	/**
	 * Class which represents the split() instruction. It returns a Map containing the tokens after the split.<br/>
	 * Parameters:<br/>
	 * 0 -> the String to be split
	 * 1 -> the String to match for splitting
	 * @author Micu Andrei
	 *
	 */
	protected class SplitInstruction extends FunctionInstruction{

		public Object code() {
			String strSplit = (String) parameters[0].code();
			String strMatch = (String) parameters[1].code();
			String[] splitting = strSplit.split(strMatch);
			HashMap<Object, Object> map = new HashMap<Object, Object>();
			for(int i=0; i<splitting.length; i++){
				map.put((Integer) i, splitting[i]);
			}
			return map;
		}
	}
	
	/**
	 * Class which represents the parseInteger() instruction. It returns an Integer if parsing was successful or .F. otherwise.<br/>
	 * Parameters:<br/>
	 * 0 -> the Integer to be parsed
	 * @author Micu Andrei
	 *
	 */
	protected class ParseIntegerInstruction extends FunctionInstruction{

		public Object code() {
			String str = (String) parameters[0].code();
			try{
				Integer parsedInteger = Integer.parseInt(str);
				return parsedInteger;
			} catch(Exception e){
				return false;
			}
		}
	}
	
	
	/* ******************** SPECIAL INSTRUCTION CLASSES ******************** */
	
	/**
	 * Class which represents an expression and doesn't return. It is used as a convenient class to manage
	 * situations when some expression must not return a value. The code() function executes the expression
	 * like a normal expression, then returns null.
	 * @author Micu Andrei
	 *
	 */
	protected class ExpressionContainerInstruction implements Instruction{
		public Instruction expression;

		public Object code() {
			expression.code();
			return null;
		}
		
	}
	
	/**
	 * Class which represents the get_next_message instruction. It removes a message from the message queue and assigns it
	 * to the currentMessage variable. The currentMessage variable can be accessed in the XML via getCurrentMessageFrom()
	 * and getCurrentMessageData() instructions. The timer represents an instruction which returns the amount of milliseconds
	 * to wait until the function returns. If no message is available after the timer expires then the currentMessage will 
	 * be null. Use isCurrentMessageNull() instruction to test if the last message was received.
	 * @author Micu Andrei
	 *
	 */
	protected class GetNextMessageInstruction implements Instruction{
		public Instruction timer;

		public Object code() {
			if(timer==null){
				currentMessage = messageList.remove();
			} else {
				currentMessage = messageList.remove((Integer)timer.code());
			}
			return null;
		}
	}
	
	/**
	 * Class which represents the send_message instruction. It sends a message containing the data expression
	 * to the automaton identified with the to expression.
	 * @author Micu Andrei
	 *
	 */
	protected class SendMessageInstruction implements Instruction{
		public Instruction to, data;

		public Object code() {
			MessageRouter.getInstance().send(to.code().toString(),
					new Message(BaseXMLAutomaton.this.name, data.code()));
			return null;
		}
		
	}
	
	protected Object[] snapshot = new Object[4];
	
	public void saveSnapshot(){
		snapshot[0] = GetDeepCopy(currentStateName);
		snapshot[1] = GetDeepCopy(currentMessage);
		snapshot[2] = GetDeepCopy(messageList);
		snapshot[3] = GetDeepCopy(variables);
	}
	
	protected Object GetDeepCopy(Object source){
		if(source == null) return null;
		try{
			ByteArrayOutputStream serialization = new ByteArrayOutputStream();
	        ObjectOutputStream serializer = new ObjectOutputStream(serialization);
	        serializer.writeObject(source);
	        serializer.flush();
	        serializer.close();
	
	        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(serialization.toByteArray()));
	        return in.readObject();
		} catch (Exception e){
			return null;
		}
	}
	
	@SuppressWarnings("unchecked")
	public void restoreSnapshot(){
		currentStateName = (String) snapshot[0];
		currentMessage = (Message) snapshot[1];
		messageList = (MessageList) snapshot[2];
		variables = (HashMap<String, Object>) snapshot[3];
	}
}
